package com.jackeysun.widget.media

import android.annotation.SuppressLint
import android.content.Context
import android.media.AudioManager
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.SeekBar
import com.jackeysun.widget.databinding.ViewAudioBinding
import java.text.SimpleDateFormat
import java.util.*

/**
 *   Created by sunxunchao on 2021/12/29.
 */
class AudioView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    companion object {
        private const val INTERVAL: Long = 1000
    }

    private val TAG = AudioView::class.java.simpleName
    var audioPlayer: AudioPlayer = AudioPlayer(context)

    private var mBinding: ViewAudioBinding =
        ViewAudioBinding.inflate(LayoutInflater.from(context), this, true)
    var path: String? = null
        set(value) {
            field = value
            audioPlayer.path = value
        }

    var speedLevel: Int = 1
        set(value) {
            field = value
            audioPlayer.speedLevel = value
        }
    var speeds = mutableListOf(1.0f)
        set(value) {
            field = value
            audioPlayer.speeds = value
        }
    var startTime: Int = 0
        set(value) {
            field = value
            audioPlayer.startTime = value
        }

    var loadResourceCompleteToPlay: Boolean = false
        set(value) {
            field = value
            audioPlayer.loadResourceCompleteToPlay = loadResourceCompleteToPlay
        }

    init {
        audioPlayer.durationHint = AudioManager.AUDIOFOCUS_GAIN
        audioPlayer.loadResourceCompleteToPlay = false
        audioPlayer.startTime = 0
        audioPlayer.onPlayerStatusChangeListener =
            object : AudioPlayer.OnPlayerStatusChangeListener {
                override fun onStatusChanged(status: SimplePlayer.Status) {
                    this@AudioView.onStatusChanged(status)
                }
            }
    }

    private val runnable: Runnable by lazy {
        object : Runnable {
            override fun run() {
                if (audioPlayer.mSimplePlayer.isPlaying()) {
                    handler?.postDelayed(this, (INTERVAL * audioPlayer.getSpeed()).toLong())
                } else {
                    handler?.removeCallbacks(runnable)
                }
                val progress = audioPlayer.mSimplePlayer.getCurrentPosition()
                mBinding.seekBar.progress = progress
                mBinding.timeStart.text =
                    progress.toLong()
                        .dateFormat("mm:ss")
            }
        }
    }

    private fun onStatusChanged(status: SimplePlayer.Status) {
        Log.d(TAG, "onStatusChanged: $status")
        mBinding.play.isSelected = false
        handler?.removeCallbacks(runnable)
        when (status) {
            SimplePlayer.Status.PREPARED -> {
                var start = audioPlayer.getCurrentPosition()
                val end = audioPlayer.getDuration()
                start = checkSeekTo(audioPlayer.startTime, IntRange(start, end))
                mBinding.timeStart.text =
                    start.toLong()
                        .dateFormat("mm:ss")
                mBinding.timeEnd.text =
                    end.toLong()
                        .dateFormat("mm:ss")
                mBinding.seekBar.post {
                    mBinding.seekBar.progress = if (start == 0) return@post else start
                }
                mBinding.seekBar.max = end
                audioPlayer.mSimplePlayer.mMediaPlayer
                    .setOnBufferingUpdateListener { mp, percent ->
                        mBinding.seekBar.secondaryProgress = end * percent / 100
                    }
                if (start != 0) {
                    audioPlayer.seekTo(start)
                }
                if (audioPlayer.loadResourceCompleteToPlay) {
                    audioPlayer.onStart()
                }
            }
            SimplePlayer.Status.PLAYING -> {
                mBinding.play.isSelected = true
                handler?.post(runnable)
            }
        }
    }


    private fun checkSeekTo(msec: Int, range: IntRange): Int =
        when {
            msec >= range.first && msec <= range.last -> msec
            else -> 0
        }

    @SuppressLint("SetTextI18n")
    override fun onFinishInflate() {
        super.onFinishInflate()
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            mBinding.speed.visibility = View.GONE
        }
        mBinding.play.setOnClickListener {
            if (audioPlayer.getStatus() == SimplePlayer.Status.PREPARED ||
                audioPlayer.getStatus() == SimplePlayer.Status.PAUSE ||
                audioPlayer.getStatus() == SimplePlayer.Status.COMPLETE
            ) {
                mBinding.speed.text = "${
                    audioPlayer.setSpeed(audioPlayer.getSpeed())
                }x"
                audioPlayer.mSimplePlayer.start()
            } else if (audioPlayer.getStatus() == SimplePlayer.Status.STOP) {
                audioPlayer.loadResourceCompleteToPlay = true
                audioPlayer.initSource()
            } else if (audioPlayer.getStatus() == SimplePlayer.Status.PLAYING) {
                audioPlayer.onPause()
            }
        }

        mBinding.seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                if (fromUser) {
                    val p = seekBar?.progress ?: 0
                    audioPlayer.seekTo(p)
                    mBinding.timeStart.text =
                        p.toLong()
                            .dateFormat("mm:ss")
                }
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}

            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        mBinding.speed.setOnClickListener {
            audioPlayer.speedLevel++
            if (audioPlayer.speedLevel >= audioPlayer.speeds.size) {
                audioPlayer.speedLevel = 0
            }
            mBinding.speed.text = "${
                if (audioPlayer.getStatus() == SimplePlayer.Status.PLAYING) {
                    audioPlayer.setSpeed(audioPlayer.getSpeed())
                } else {
                    audioPlayer.getSpeed()
                }
            }x"
        }
    }

    override fun onVisibilityAggregated(isVisible: Boolean) {
        super.onVisibilityAggregated(isVisible)
        if (isVisible) {
//            mAbsPlayer.start()
        } else {
            audioPlayer.onPause()
        }
    }

    fun onStart() {
        audioPlayer.onStart()
    }

    fun onPause() {
        audioPlayer.onPause()
    }

    fun onStop() {
        audioPlayer.onStop()
    }

    fun release() {
        audioPlayer.release()
    }

}

@SuppressLint("SimpleDateFormat")
fun Long.dateFormat(pattern: String): String =
    try {
        val simpleDateFormat = SimpleDateFormat(pattern)
        simpleDateFormat.format(Date(this))
    } catch (e: Exception) {
        ""
    }
